<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>第三方语音识别服务集成示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      line-height: 1.6;
    }
    
    h1 {
      color: #333;
      border-bottom: 1px solid #eee;
      padding-bottom: 10px;
    }
    
    .container {
      margin-top: 20px;
    }
    
    .section {
      margin-bottom: 30px;
      padding: 15px;
      border: 1px solid #ddd;
      border-radius: 5px;
      background-color: #f9f9f9;
    }
    
    .section h2 {
      margin-top: 0;
      font-size: 1.2em;
      color: #444;
    }
    
    button {
      padding: 8px 16px;
      background-color: #4CAF50;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      margin-right: 10px;
      margin-bottom: 10px;
    }
    
    button:hover {
      background-color: #45a049;
    }
    
    button:disabled {
      background-color: #cccccc;
      cursor: not-allowed;
    }
    
    .audio-level {
      height: 20px;
      background-color: #eee;
      border-radius: 3px;
      margin-top: 10px;
      overflow: hidden;
    }
    
    .audio-level-bar {
      height: 100%;
      width: 0%;
      background-color: #4CAF50;
      transition: width 0.1s ease-out;
    }
    
    .status {
      margin-top: 10px;
      padding: 10px;
      background-color: #f5f5f5;
      border-radius: 3px;
    }
    
    .recognition-result {
      margin-top: 20px;
      padding: 15px;
      background-color: #fff;
      border: 1px solid #ddd;
      border-radius: 5px;
      min-height: 100px;
      max-height: 300px;
      overflow-y: auto;
    }
    
    .log-container {
      height: 150px;
      overflow-y: auto;
      background-color: #f5f5f5;
      padding: 10px;
      border-radius: 3px;
      font-family: monospace;
      font-size: 0.9em;
    }
    
    .service-selector {
      margin-bottom: 15px;
    }
    
    .service-selector select {
      padding: 8px;
      border-radius: 4px;
      border: 1px solid #ddd;
      margin-right: 10px;
    }
    
    .api-config {
      margin-bottom: 15px;
      padding: 10px;
      background-color: #f0f0f0;
      border-radius: 4px;
    }
    
    .api-config input {
      width: 100%;
      padding: 8px;
      margin-top: 5px;
      margin-bottom: 10px;
      border-radius: 4px;
      border: 1px solid #ddd;
    }
    
    .api-config label {
      font-weight: bold;
    }
    
    .tabs {
      display: flex;
      margin-bottom: 15px;
      border-bottom: 1px solid #ddd;
    }
    
    .tab {
      padding: 10px 15px;
      cursor: pointer;
      background-color: #f0f0f0;
      border: 1px solid #ddd;
      border-bottom: none;
      border-radius: 4px 4px 0 0;
      margin-right: 5px;
    }
    
    .tab.active {
      background-color: #fff;
      border-bottom: 1px solid #fff;
      margin-bottom: -1px;
    }
    
    .tab-content {
      display: none;
    }
    
    .tab-content.active {
      display: block;
    }
  </style>
</head>
<body>
  <h1>第三方语音识别服务集成示例</h1>
  
  <div class="container">
    <div class="section">
      <h2>语音识别服务集成</h2>
      <p>此示例展示了如何将麦克风SDK与各种第三方语音识别服务集成。选择一个服务并配置API密钥以开始使用。</p>
      
      <div class="service-selector">
        <label for="service-select">选择语音识别服务:</label>
        <select id="service-select">
          <option value="mock">模拟服务 (演示用)</option>
          <option value="azure">Microsoft Azure 语音服务</option>
          <option value="google">Google Speech-to-Text</option>
          <option value="baidu">百度语音识别</option>
        </select>
      </div>
      
      <div id="mock-config" class="api-config">
        <p>模拟服务不需要API密钥。此服务仅用于演示，将生成随机文本作为识别结果。</p>
      </div>
      
      <div id="azure-config" class="api-config" style="display: none;">
        <label for="azure-key">Azure 订阅密钥:</label>
        <input type="text" id="azure-key" placeholder="输入您的Azure语音服务订阅密钥">
        <label for="azure-region">Azure 区域:</label>
        <input type="text" id="azure-region" placeholder="例如: eastasia, southeastasia" value="eastasia">
      </div>
      
      <div id="google-config" class="api-config" style="display: none;">
        <label for="google-key">Google API 密钥:</label>
        <input type="text" id="google-key" placeholder="输入您的Google API密钥">
        <p>注意: 在实际应用中，应使用服务器端代理来保护您的API密钥。</p>
      </div>
      
      <div id="baidu-config" class="api-config" style="display: none;">
        <label for="baidu-app-id">百度 App ID:</label>
        <input type="text" id="baidu-app-id" placeholder="输入您的百度语音App ID">
        <label for="baidu-api-key">百度 API Key:</label>
        <input type="text" id="baidu-api-key" placeholder="输入您的百度语音API Key">
        <label for="baidu-secret-key">百度 Secret Key:</label>
        <input type="text" id="baidu-secret-key" placeholder="输入您的百度语音Secret Key">
      </div>
      
      <div class="controls">
        <button id="start-btn">开始录音</button>
        <button id="stop-btn" disabled>停止录音</button>
        <button id="clear-btn">清除结果</button>
      </div>
      
      <div class="audio-level">
        <div id="level-bar" class="audio-level-bar"></div>
      </div>
      
      <div class="status">
        <div id="mic-status">麦克风状态: 未启动</div>
        <div id="service-status">服务状态: 未连接</div>
      </div>
      
      <div class="tabs">
        <div class="tab active" data-tab="results">识别结果</div>
        <div class="tab" data-tab="logs">日志</div>
      </div>
      
      <div id="results-tab" class="tab-content active">
        <div class="recognition-result" id="result-container"></div>
      </div>
      
      <div id="logs-tab" class="tab-content">
        <div class="log-container" id="service-log"></div>
      </div>
    </div>
    
    <div class="section">
      <h2>实现说明</h2>
      <p>此示例演示了三种与第三方语音识别服务集成的方法：</p>
      
      <ol>
        <li><strong>模拟服务</strong>: 用于演示和测试，不需要外部API。</li>
        <li><strong>Microsoft Azure</strong>: 使用Azure语音SDK，直接接受麦克风流。</li>
        <li><strong>Google/百度</strong>: 使用音频数据回调，处理音频数据后发送到API。</li>
      </ol>
      
      <p>在实际应用中，应考虑以下几点：</p>
      <ul>
        <li>API密钥应存储在服务器端，而不是客户端代码中。</li>
        <li>对于生产环境，应实现更复杂的错误处理和重试机制。</li>
        <li>某些服务可能需要特定的音频格式或采样率。</li>
      </ul>
    </div>
  </div>
  
  <script type="module">
    import MicrophoneSDK from '../MicrophoneSDK.js';
    
    // 等待DOM加载完成
    document.addEventListener('DOMContentLoaded', async () => {
      // 初始化SDK
      await MicrophoneSDK.initialize();
      
      // 获取DOM元素
      const startBtn = document.getElementById('start-btn');
      const stopBtn = document.getElementById('stop-btn');
      const clearBtn = document.getElementById('clear-btn');
      const levelBar = document.getElementById('level-bar');
      const micStatus = document.getElementById('mic-status');
      const serviceStatus = document.getElementById('service-status');
      const resultContainer = document.getElementById('result-container');
      const serviceLog = document.getElementById('service-log');
      const serviceSelect = document.getElementById('service-select');
      
      // 配置元素
      const mockConfig = document.getElementById('mock-config');
      const azureConfig = document.getElementById('azure-config');
      const googleConfig = document.getElementById('google-config');
      const baiduConfig = document.getElementById('baidu-config');
      
      // 标签页元素
      const tabs = document.querySelectorAll('.tab');
      const tabContents = document.querySelectorAll('.tab-content');
      
      // 服务状态变量
      let currentService = 'mock';
      let isRecognizing = false;
      let unsubscribeAudioData = null;
      let recognitionService = null;
      
      // 模拟语音识别服务
      class MockRecognitionService {
        constructor() {
          this.isRunning = false;
          this.mockPhrases = [
            "这是一个模拟的语音识别结果",
            "麦克风SDK支持多种语音识别服务集成",
            "您可以轻松地将音频数据发送到第三方服务",
            "语音识别技术正在快速发展",
            "人工智能和机器学习提高了语音识别的准确性",
            "这只是一个演示，实际应用中应使用真实的语音识别服务"
          ];
          this.mockInterval = null;
        }
        
        start() {
          if (this.isRunning) return;
          
          this.isRunning = true;
          logService('模拟服务已启动');
          
          // 模拟识别结果
          this.mockInterval = setInterval(() => {
            const randomPhrase = this.mockPhrases[Math.floor(Math.random() * this.mockPhrases.length)];
            this.addResult(randomPhrase);
          }, 3000);
          
          return true;
        }
        
        stop() {
          if (!this.isRunning) return;
          
          this.isRunning = false;
          clearInterval(this.mockInterval);
          logService('模拟服务已停止');
          
          return true;
        }
        
        addResult(text) {
          const resultElement = document.createElement('p');
          resultElement.textContent = text;
          resultContainer.appendChild(resultElement);
          resultContainer.scrollTop = resultContainer.scrollHeight;
        }
      }
      
      // Azure语音识别服务
      class AzureRecognitionService {
        constructor(key, region) {
          this.key = key;
          this.region = region;
          this.isRunning = false;
          this.recognizer = null;
        }
        
        async start() {
          if (this.isRunning) return;
          
          if (!this.key || !this.region) {
            logService('错误: 缺少Azure密钥或区域');
            return false;
          }
          
          try {
            // 在实际应用中，您需要引入Microsoft Azure语音SDK
            // 这里我们只是模拟其行为
            logService('正在连接到Azure语音服务...');
            
            // 获取麦克风流
            const microphoneStream = MicrophoneSDK.getMicrophoneStream();
            
            if (!microphoneStream) {
              logService('错误: 无法获取麦克风流');
              return false;
            }
            
            // 模拟Azure SDK行为
            this.isRunning = true;
            logService(`已连接到Azure语音服务 (区域: ${this.region})`);
            
            // 模拟识别结果
            setTimeout(() => {
              this.addResult("这是一个模拟的Azure语音识别结果。在实际应用中，您需要引入Microsoft Azure语音SDK。");
            }, 2000);
            
            return true;
          } catch (error) {
            logService(`错误: ${error.message}`);
            return false;
          }
        }
        
        stop() {
          if (!this.isRunning) return;
          
          this.isRunning = false;
          logService('已断开与Azure语音服务的连接');
          
          return true;
        }
        
        addResult(text) {
          const resultElement = document.createElement('p');
          resultElement.textContent = text;
          resultContainer.appendChild(resultElement);
          resultContainer.scrollTop = resultContainer.scrollHeight;
        }
      }
      
      // Google语音识别服务
      class GoogleRecognitionService {
        constructor(apiKey) {
          this.apiKey = apiKey;
          this.isRunning = false;
          this.audioChunks = [];
        }
        
        start() {
          if (this.isRunning) return;
          
          if (!this.apiKey) {
            logService('错误: 缺少Google API密钥');
            return false;
          }
          
          this.isRunning = true;
          this.audioChunks = [];
          logService('已连接到Google语音识别服务');
          
          // 注册音频数据回调
          unsubscribeAudioData = MicrophoneSDK.registerAudioDataCallback(data => {
            if (!this.isRunning) return;
            
            // 处理音频数据
            this.processAudioData(data);
          });
          
          return true;
        }
        
        stop() {
          if (!this.isRunning) return;
          
          this.isRunning = false;
          
          // 取消注册音频数据回调
          if (unsubscribeAudioData) {
            unsubscribeAudioData();
            unsubscribeAudioData = null;
          }
          
          // 发送最后的音频数据
          this.sendAudioForRecognition();
          
          logService('已断开与Google语音识别服务的连接');
          
          return true;
        }
        
        processAudioData(data) {
          // 将音频数据添加到缓冲区
          this.audioChunks.push(data.audioData);
          
          // 当缓冲区达到一定大小时发送数据
          if (this.audioChunks.length >= 10) {
            this.sendAudioForRecognition();
          }
        }
        
        sendAudioForRecognition() {
          if (this.audioChunks.length === 0) return;
          
          // 合并音频数据
          const totalLength = this.audioChunks.reduce((acc, chunk) => acc + chunk.length, 0);
          const mergedData = new Float32Array(totalLength);
          
          let offset = 0;
          for (const chunk of this.audioChunks) {
            mergedData.set(chunk, offset);
            offset += chunk.length;
          }
          
          // 清空缓冲区
          this.audioChunks = [];
          
          // 模拟发送到Google API
          logService(`发送音频数据到Google API (${totalLength} 样本)`);
          
          // 模拟识别结果
          setTimeout(() => {
            this.addResult("这是一个模拟的Google语音识别结果。在实际应用中，您需要发送音频数据到Google Speech-to-Text API。");
          }, 1000);
        }
        
        addResult(text) {
          const resultElement = document.createElement('p');
          resultElement.textContent = text;
          resultContainer.appendChild(resultElement);
          resultContainer.scrollTop = resultContainer.scrollHeight;
        }
      }
      
      // 百度语音识别服务
      class BaiduRecognitionService {
        constructor(appId, apiKey, secretKey) {
          this.appId = appId;
          this.apiKey = apiKey;
          this.secretKey = secretKey;
          this.isRunning = false;
          this.audioChunks = [];
        }
        
        start() {
          if (this.isRunning) return;
          
          if (!this.appId || !this.apiKey || !this.secretKey) {
            logService('错误: 缺少百度API参数');
            return false;
          }
          
          this.isRunning = true;
          this.audioChunks = [];
          logService('已连接到百度语音识别服务');
          
          // 注册音频数据回调
          unsubscribeAudioData = MicrophoneSDK.registerAudioDataCallback(data => {
            if (!this.isRunning) return;
            
            // 处理音频数据
            this.processAudioData(data);
          });
          
          return true;
        }
        
        stop() {
          if (!this.isRunning) return;
          
          this.isRunning = false;
          
          // 取消注册音频数据回调
          if (unsubscribeAudioData) {
            unsubscribeAudioData();
            unsubscribeAudioData = null;
          }
          
          // 发送最后的音频数据
          this.sendAudioForRecognition();
          
          logService('已断开与百度语音识别服务的连接');
          
          return true;
        }
        
        processAudioData(data) {
          // 将音频数据添加到缓冲区
          this.audioChunks.push(data.audioData);
          
          // 当缓冲区达到一定大小时发送数据
          if (this.audioChunks.length >= 10) {
            this.sendAudioForRecognition();
          }
        }
        
        sendAudioForRecognition() {
          if (this.audioChunks.length === 0) return;
          
          // 合并音频数据
          const totalLength = this.audioChunks.reduce((acc, chunk) => acc + chunk.length, 0);
          const mergedData = new Float32Array(totalLength);
          
          let offset = 0;
          for (const chunk of this.audioChunks) {
            mergedData.set(chunk, offset);
            offset += chunk.length;
          }
          
          // 清空缓冲区
          this.audioChunks = [];
          
          // 模拟发送到百度API
          logService(`发送音频数据到百度API (${totalLength} 样本)`);
          
          // 模拟识别结果
          setTimeout(() => {
            this.addResult("这是一个模拟的百度语音识别结果。在实际应用中，您需要发送音频数据到百度语音识别API。");
          }, 1000);
        }
        
        addResult(text) {
          const resultElement = document.createElement('p');
          resultElement.textContent = text;
          resultContainer.appendChild(resultElement);
          resultContainer.scrollTop = resultContainer.scrollHeight;
        }
      }
      
      // 创建识别服务实例
      function createRecognitionService() {
        switch (currentService) {
          case 'mock':
            return new MockRecognitionService();
          
          case 'azure':
            const azureKey = document.getElementById('azure-key').value;
            const azureRegion = document.getElementById('azure-region').value;
            return new AzureRecognitionService(azureKey, azureRegion);
          
          case 'google':
            const googleKey = document.getElementById('google-key').value;
            return new GoogleRecognitionService(googleKey);
          
          case 'baidu':
            const baiduAppId = document.getElementById('baidu-app-id').value;
            const baiduApiKey = document.getElementById('baidu-api-key').value;
            const baiduSecretKey = document.getElementById('baidu-secret-key').value;
            return new BaiduRecognitionService(baiduAppId, baiduApiKey, baiduSecretKey);
          
          default:
            return new MockRecognitionService();
        }
      }
      
      // 开始录音和识别
      async function startRecording() {
        try {
          // 创建识别服务
          recognitionService = createRecognitionService();
          
          // 开始麦克风录音
          await MicrophoneSDK.startListening();
          
          // 启动识别服务
          const serviceStarted = recognitionService.start();
          
          if (!serviceStarted) {
            await MicrophoneSDK.stopListening();
            serviceStatus.textContent = '服务状态: 连接失败';
            return;
          }
          
          // 更新UI
          startBtn.disabled = true;
          stopBtn.disabled = false;
          micStatus.textContent = '麦克风状态: 已启动';
          serviceStatus.textContent = '服务状态: 已连接';
          isRecognizing = true;
        } catch (error) {
          console.error('启动录音失败:', error);
          logService(`错误: 启动录音失败 - ${error.message}`);
        }
      }
      
      // 停止录音和识别
      async function stopRecording() {
        try {
          // 停止识别服务
          if (recognitionService) {
            recognitionService.stop();
          }
          
          // 停止麦克风录音
          await MicrophoneSDK.stopListening();
          
          // 更新UI
          startBtn.disabled = false;
          stopBtn.disabled = true;
          micStatus.textContent = '麦克风状态: 已停止';
          serviceStatus.textContent = '服务状态: 已断开';
          isRecognizing = false;
        } catch (error) {
          console.error('停止录音失败:', error);
          logService(`错误: 停止录音失败 - ${error.message}`);
        }
      }
      
      // 清除识别结果
      function clearResults() {
        resultContainer.innerHTML = '';
      }
      
      // 记录服务日志
      function logService(message) {
        const logEntry = document.createElement('div');
        logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
        serviceLog.appendChild(logEntry);
        serviceLog.scrollTop = serviceLog.scrollHeight;
      }
      
      // 显示选中的服务配置
      function showServiceConfig(service) {
        // 隐藏所有配置
        mockConfig.style.display = 'none';
        azureConfig.style.display = 'none';
        googleConfig.style.display = 'none';
        baiduConfig.style.display = 'none';
        
        // 显示选中的配置
        switch (service) {
          case 'mock':
            mockConfig.style.display = 'block';
            break;
          case 'azure':
            azureConfig.style.display = 'block';
            break;
          case 'google':
            googleConfig.style.display = 'block';
            break;
          case 'baidu':
            baiduConfig.style.display = 'block';
            break;
        }
      }
      
      // 切换标签页
      function switchTab(tabId) {
        // 更新标签页状态
        tabs.forEach(tab => {
          if (tab.dataset.tab === tabId) {
            tab.classList.add('active');
          } else {
            tab.classList.remove('active');
          }
        });
        
        // 更新内容区域
        tabContents.forEach(content => {
          if (content.id === `${tabId}-tab`) {
            content.classList.add('active');
          } else {
            content.classList.remove('active');
          }
        });
      }
      
      // 监听音频电平变化
      MicrophoneSDK.onAudioLevelChange(level => {
        levelBar.style.width = `${level * 100}%`;
      });
      
      // 监听麦克风状态变化
      MicrophoneSDK.onMicrophoneStatusChange(status => {
        micStatus.textContent = `麦克风状态: ${status.isListening ? '已启动' : '已停止'}`;
      });
      
      // 设置按钮事件处理器
      startBtn.addEventListener('click', startRecording);
      stopBtn.addEventListener('click', stopRecording);
      clearBtn.addEventListener('click', clearResults);
      
      // 设置服务选择事件处理器
      serviceSelect.addEventListener('change', () => {
        currentService = serviceSelect.value;
        showServiceConfig(currentService);
        logService(`已选择服务: ${serviceSelect.options[serviceSelect.selectedIndex].text}`);
      });
      
      // 设置标签页事件处理器
      tabs.forEach(tab => {
        tab.addEventListener('click', () => {
          switchTab(tab.dataset.tab);
        });
      });
      
      // 初始化
      showServiceConfig(currentService);
      logService('页面已加载，SDK已初始化');
      logService('已选择服务: 模拟服务 (演示用)');
      
      // 配置音频处理
      MicrophoneSDK.setAudioProcessingConfig({
        enabled: true,
        bufferSize: 4096,
        inputChannels: 1,
        outputChannels: 1
      });
    });
  </script>
</body>
</html> 